namespace SimpleWebServices.Models
{
    using System;
    using System.Collections.ObjectModel;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Xml.XPath;
    using SimpleWebServices;
    using SimpleWebServices.Security.Cryptography;
    using SimpleWebServices.Xml;
    using Xunit;

    public sealed class SiteMapUrlSetFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<SiteMapUrlSet>()
                .DerivesFrom<SimpleWebServices.Data.Record>()
                .IsConcreteClass()
                .IsSealed()
                .HasDefaultConstructor()
                .XmlRoot("urlset", "http://www.sitemaps.org/schemas/sitemap/0.9")
                .Implements<IXmlSerializable>()
                .Implements<IXmlSerializerNamespaces>()
                .Result);
        }

        [Fact]
        public void deserialize()
        {
            SiteMapUrlSet actual = (
                "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>" +
                    "<url>" +
                        "<changefreq>weekly</changefreq>" +
                        "<loc>http://example.com/location</loc>" +
                        "<lastmod>1999-12-31T01:02:03</lastmod>" +
                        "<priority>0.5</priority>" +
                    "</url>" +
                "</urlset>").Deserialize<SiteMapUrlSet>();

            Assert.NotNull(actual);

            SiteMapUrl url = actual.Objects[0] as SiteMapUrl;
            Assert.Equal<string>("weekly", url.ChangeFrequency);
            Assert.Equal<DateTime>(new DateTime(1999, 12, 31, 1, 2, 3), url.LastModified.Value);
            Assert.Equal<AbsoluteUri>("http://example.com/location", url.Location);
            Assert.Equal<float>(0.5f, url.Priority.Value);
        }

        [Fact]
        public void deserialize_whenPublisher()
        {
            SiteMapUrlSet actual = (
                "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>" +
                    "<publisher type='" + typeof(TestIPublishSiteMapUrls).AssemblyQualifiedName + "' />" +
                "</urlset>").Deserialize<SiteMapUrlSet>();

            Assert.NotNull(actual);

            SiteMapUrl url = actual.Objects[0] as SiteMapUrl;

            Assert.Equal<AbsoluteUri>(TestIPublishSiteMapUrls.Url.Location, url.Location);
        }

        [Fact]
        public void deserialize_whenFoldedPublisher()
        {
            SiteMapUrlSet actual = (
                "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' xmlns:fold='urn://simplewebservices/fold'>" +
                    "<fold:publisher xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' type='" + typeof(TestIPublishSiteMapUrls).AssemblyQualifiedName + "' />" +
                "</urlset>").Deserialize<SiteMapUrlSet>();

            Assert.NotNull(actual);

            Assert.IsAssignableFrom<SiteMapPublisher>(actual.Objects[0]);
        }

        [Fact]
        public void deserializeEmpty()
        {
            SiteMapUrlSet actual = "<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9' />".Deserialize<SiteMapUrlSet>();

            Assert.NotNull(actual);

            Assert.Empty(actual.Objects);
        }

        [Fact]
        public void serialize()
        {
            SiteMapUrlSet obj = new SiteMapUrlSet
            {
                Objects =
                {
                    new SiteMapUrl
                    {
                        ChangeFrequency = "daily",
                        LastModified = new DateTime(1999, 12, 31),
                        Location = "http://example.com/location",
                        Priority = 0.5f
                    },
                    new SiteMapPublisher
                    {
                        Type = typeof(TestIPublishSiteMapUrls)
                    }
                }
            };

            XPathNavigator navigator = obj.Serialize().CreateNavigator();

            XmlNamespaceManager namespaces = new XmlNamespaceManager(navigator.NameTable);
            namespaces.AddNamespace("s", "http://www.sitemaps.org/schemas/sitemap/0.9");

            Assert.True(navigator.OuterXml.StartsWith("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\""));

            Assert.True((bool)navigator.Evaluate("1=count(/s:urlset/s:url/s:changefreq[text()='daily'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:urlset/s:url/s:lastmod[text()='1999-12-31'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:urlset/s:url/s:loc[text()='http://example.com/location'])", namespaces));
            Assert.True((bool)navigator.Evaluate("1=count(/s:urlset/s:url/s:priority[text()='0.5'])", namespaces));

            Assert.True((bool)navigator.Evaluate("1=count(/s:urlset/s:publisher[@type='SimpleWebServices.Models.TestIPublishSiteMapUrls, SimpleWebServices.Mvc.Facts'])", namespaces));
        }

        [Fact]
        public void ctor()
        {
            Assert.NotNull(new SiteMapUrlSet());
        }

        [Fact]
        public void prop_Entity()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrlSet).GetProperty("Entity"))
                .TypeIs<string>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_Entity_get()
        {
            SiteMapUrlSet obj = new SiteMapUrlSet
            {
                Objects =
                {
                    new SiteMapUrl
                    {
                        ChangeFrequency = "daily",
                        LastModified = new DateTime(1999, 12, 31),
                        Location = "http://example.com/location",
                        Priority = 0.5f
                    },
                    new SiteMapPublisher
                    {
                        Type = typeof(TestIPublishSiteMapUrls)
                    }
                }
            };

            string expected = "UZvQbSDDeljz+h+HZSlOlQ==";
            string actual = MD5Hash.Compute(obj.Entity);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Entity_getEmpty()
        {
            string expected = string.Empty;
            string actual = new SiteMapUrlSet().Entity;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Objects()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrlSet).GetProperty("Objects"))
                .TypeIs<Collection<object>>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_XmlNamespaceDeclarations()
        {
            Assert.True(new PropertyExpectations(typeof(SiteMapUrlSet).GetProperty("XmlNamespaceDeclarations"))
                .XmlNamespaceDeclarations()
                .TypeIs<XmlSerializerNamespaces>()
                .DefaultValueIsNotNull()
                .Result);
        }

        [Fact]
        public void prop_XmlNamespaceDeclarations_get()
        {
            XmlSerializerNamespaces actual = new SiteMapUrlSet().XmlNamespaceDeclarations;

            Assert.Equal<int>(1, actual.Count);

            XmlQualifiedName name = actual.ToArray().GetValue(0) as XmlQualifiedName;
            Assert.Equal<string>(string.Empty, name.Name);
            Assert.Equal<string>("http://www.sitemaps.org/schemas/sitemap/0.9", name.Namespace);
        }

        [Fact]
        public void IXmlSerializable_op_GetSchema()
        {
            Assert.Throws<NotSupportedException>(() => (new SiteMapUrlSet() as IXmlSerializable).GetSchema());
        }

        [Fact]
        public void IXmlSerializable_op_ReadXml_XmlReaderNull()
        {
            Assert.Throws<ArgumentNullException>(() => (new SiteMapUrlSet() as IXmlSerializable).ReadXml(null as XmlReader));
        }

        [Fact]
        public void IXmlSerializable_op_WriteXml_XmlWriterNull()
        {
            Assert.Throws<ArgumentNullException>(() => (new SiteMapUrlSet() as IXmlSerializable).WriteXml(null as XmlWriter));
        }
    }
}